home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Games / Xconq 7.1.0 / src / xconq-7.1.0 / kernel / module.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-07-07  |  20.3 KB  |  813 lines  |  [TEXT/R*ch]

  1. /* Game modules for Xconq.
  2.    Copyright (C) 1991, 1992, 1993, 1994 Stanley T. Shebs.
  3.  
  4. Xconq is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2, or (at your option)
  7. any later version.  See the file COPYING.  */
  8.  
  9. #include "conq.h"
  10.  
  11. extern char *readerrbuf;
  12.  
  13. static void do_one_variant PARAMS ((Module *module, struct a_variant *var, Obj *varsetdata));
  14.  
  15. /* List of all known modules. Their descriptions can co-exist in memory,
  16.    even if their contents cannot. */
  17.  
  18. Module *modulelist;
  19.  
  20. /* The main module defining the game in effect. */
  21.  
  22. Module *mainmodule;
  23.  
  24. char *moduledesigbuf = NULL;
  25.  
  26. /* Empty out the list of modules. */
  27.  
  28. void
  29. clear_game_modules()
  30. {
  31.     modulelist = mainmodule = NULL;
  32. }
  33.  
  34. /* Create a brand-new game module. */
  35.  
  36. Module *
  37. create_game_module(name)
  38. char *name;
  39. {
  40.     Module *module = (Module *) xmalloc(sizeof(Module));
  41.  
  42.     /* Fill in nonzero slots. */
  43.     /* The module's name must never be NULL. */
  44.     if (name == NULL)
  45.       name = "";
  46.     module->name = name;
  47.     module->instructions = lispnil;
  48.     module->notes = lispnil;
  49.     module->designnotes = lispnil;
  50.     module->startlineno = 1;
  51.     module->endlineno = 1;
  52.     /* Add to front of module list. */
  53.     module->next = modulelist;
  54.     modulelist = module;
  55.     return module;
  56. }
  57.  
  58. Module *
  59. find_game_module(name)
  60. char *name;
  61. {
  62.     Module *module;
  63.  
  64.     if (name != NULL) {
  65.     for_all_modules(module) {
  66.         if (module->name && strcmp(name, module->name) == 0)
  67.           return module;
  68.     }
  69.     }
  70.     return NULL;
  71. }
  72.  
  73.  
  74. /* Produce a module of the given name, either by finding it or creating it. */
  75.  
  76. Module *
  77. get_game_module(name)
  78. char *name;
  79. {
  80.     Module *module = find_game_module(name);
  81.  
  82.     if (module != NULL)
  83.       return module;
  84.     return create_game_module(name);
  85. }
  86.  
  87. /* Make a game module for the given name and maybe bolt it into the include
  88.    list of another module. */
  89.  
  90. Module *
  91. add_game_module(name, includer)
  92. char *name;
  93. Module *includer;
  94. {
  95.     Module *module = get_game_module(name), *other;
  96.  
  97.     if (includer) {
  98.     /* Add to the end of the list of include files. */
  99.     if (includer->include == NULL) {
  100.         includer->include = includer->lastinclude = module;
  101.     } else {
  102.         for (other = includer->include; other != NULL; other = other->nextinclude) {
  103.         /* already here, just return it. */
  104.         if (module == other)
  105.           return module;
  106.         }
  107.         includer->lastinclude->nextinclude = module;
  108.         includer->lastinclude = module;
  109.     }
  110.     } else {
  111.     /* an error? */
  112.     }
  113.     return module;
  114. }
  115.  
  116. /* Display game module info to a side. */
  117.  
  118. void
  119. describe_game_modules(arg, key, buf)
  120. int arg;
  121. char *key, *buf;
  122. {
  123.     if (mainmodule != NULL) {
  124.     /* First put out basic module info. */
  125.     describe_game_module_aux(buf, mainmodule, 0);
  126.     /* Now do the lengthy module notes (with no indentation). */
  127.     describe_module_notes(buf, mainmodule);
  128.     } else {
  129.     sprintf(buf, "(No game module information is available.)");
  130.     }
  131. }
  132.  
  133. /* Recurse down through included modules to display docs on each.
  134.    Indents each file by inclusion level.  Note that modules cannot
  135.    be loaded more than once, so each will be described only once here. */
  136.  
  137. void   
  138. describe_game_module_aux(buf, module, level)
  139. char *buf;
  140. Module *module;
  141. int level;
  142. {
  143.     int i;
  144.     char indentbuf[100];
  145.     Module *submodule;
  146.  
  147.     indentbuf[0] = '\0';
  148.     for (i = 0; i < level; ++i) {
  149.     strcat(indentbuf, "  ");
  150.     }
  151.     tprintf(buf, "%s\"%s\"", indentbuf,
  152.         (module->title ? module->title : module->name));
  153.     if (module->title == NULL) {
  154.     tprintf(buf, " (\"%s\")", module->name);
  155.     }
  156.     if (module->version != NULL) {
  157.     tprintf(buf, " (version \"%s\")", module->version);
  158.     }
  159.     tprintf(buf, "\n");
  160.     tprintf(buf, "%s          %s\n",
  161.         indentbuf,
  162.         (module->blurb ? module->blurb : "(no description)"));
  163.     if (module->notes != lispnil) {
  164.     tprintf(buf, "%s          (See notes below)\n", indentbuf);
  165.     }
  166.     /* Now describe any included modules. */
  167.     for_all_includes(module, submodule) {
  168.     describe_game_module_aux(buf, submodule, level + 1);
  169.     }
  170. }
  171.  
  172. /* Dump the module player's and designer's notes into the given buffer. */
  173.  
  174. void
  175. describe_module_notes(buf, module)
  176. char *buf;
  177. Module *module;
  178. {
  179.     Module *submodule;
  180.  
  181.     if (module->notes != lispnil) {
  182.     tprintf(buf, "\nNotes to \"%s\":\n", module->name);
  183.     append_notes(buf, module->notes);
  184.     }
  185. #ifdef DESIGNERS
  186.     /* Only show design notes if any designers around. */
  187.     if (numdesigners > 0 && module->designnotes != lispnil) {
  188.     tprintf(buf, "\nDesign Notes to \"%s\":\n", module->name);
  189.     append_notes(buf, module->designnotes);
  190.     }
  191. #endif /* DESIGNERS */
  192.     for_all_includes(module, submodule) {
  193.     describe_module_notes(buf, submodule);
  194.     }
  195. }
  196.  
  197. /* Sometimes we find ourselves lacking a game to provide meaning and
  198.    context for interpretation; this routine loads the standard game
  199.    (or a specified alternative default) immediately, but only makes
  200.    it the main module if none defined. */
  201.  
  202. void
  203. load_default_game()
  204. {
  205.     extern char *standard_game_name;
  206.     char *defaultname = standard_game_name;
  207.     Module *module, *module2;
  208.  
  209.     /* If we have a different default module, use it instead. */
  210.     if (mainmodule != NULL
  211.     && !empty_string(mainmodule->defaultbasemodulename)) {
  212.         defaultname = mainmodule->defaultbasemodulename;
  213.     }
  214.     module = get_game_module(defaultname);
  215.     if (mainmodule == NULL)
  216.       mainmodule = module;
  217.     load_game_description(module);
  218.     /* Recurse one level of default base module. */
  219.     /* (should recurse indefinitely, or not?) */
  220.     if (!empty_string(module->defaultbasemodulename)) {
  221.     module2 = get_game_module(module->defaultbasemodulename);
  222.     load_game_module(module2, TRUE);
  223.     }
  224.     load_game_module(module, TRUE);
  225. }
  226.  
  227. /* Attempt to read just the first form in a module and use it as a
  228.    description of the module.  Return true if this worked, false
  229.    otherwise. */
  230.  
  231. int
  232. load_game_description(module)
  233. Module *module;
  234. {
  235.     Obj *form, *thecar;
  236.     char *name;
  237.  
  238.     if (open_module(module, FALSE)) {
  239.     if ((form = read_form(module->fp,
  240.                   &(module->startlineno),
  241.                   &(module->endlineno)))
  242.         != lispeof) {
  243.         if (consp(form) && symbolp(thecar = car(form))) {
  244.         name = c_string(thecar);
  245.         if (keyword_code(name) == K_GAME_MODULE) {
  246.             interp_game_module(form, module);
  247.             close_module(module);
  248.             /* Note that module is still not considered "loaded". */
  249.             return TRUE;
  250.         }
  251.         }
  252.     }
  253.     }
  254.     return FALSE;
  255. }
  256.  
  257. /* Game files can live in library directories or somewhere else.  This
  258.    function tries to find a file, open it, and load the contents. */
  259.  
  260. void
  261. load_game_module(module, dowarn)
  262. Module *module;
  263. int dowarn;
  264. {
  265.     char ch;
  266.  
  267.     if (open_module(module, dowarn)) {
  268.     if (module->fp) {
  269.         /* Peek at the first character - was 'X' in old format files. */
  270.         ch = getc(module->fp);
  271.         ungetc(ch, module->fp);
  272.         if (ch == 'X') {
  273.         init_error("\"%s\" is probably an obsolete Xconq file; in any case, it cannot be used.",
  274.                module->filename);
  275.         } else {
  276.         /* New format, read it all. */
  277.         read_forms(module);
  278.         }
  279.     } else {
  280.         /* (should be able to read from contents string) */
  281.     }
  282.     /* We're done, can close. */
  283.     close_module(module);
  284.     /* Mark the module as having been loaded - note that this will happen
  285.        even if there were horrible errors. */
  286.     module->loaded = TRUE;
  287.     /* If the turn number has been set explicitly to a positive value,
  288.        assume that a saved game is being restored into the middle of the turn. */
  289.     if (g_turn() > 0)
  290.       midturnrestore = TRUE;
  291.     /* If the random state has been set explicitly to a nonnegative value,
  292.        use it to reseed the generator. */
  293.     if (g_random_state() >= 0)
  294.       init_xrandom(g_random_state());
  295.     /* Make all the cross-references right. */
  296.     patch_object_references();
  297.     /* Are all the types staked down now? */
  298.     if (!canaddutype && !canaddmtype && !canaddttype) {
  299.         typesdefined = TRUE;
  300.         /* (should also record this as a sort of base module?) */
  301.     }
  302.     }
  303. }
  304.  
  305. void
  306. load_base_module(module)
  307. Module *module;
  308. {
  309.     char *basename = module->basemodulename;
  310.     Module *basemodule;
  311.  
  312.     if (!empty_string(basename)) {
  313.     basemodule = find_game_module(basename);
  314.     if (basemodule == NULL)
  315.       basemodule = add_game_module(basename, module);
  316.     if (basemodule->loaded) {    
  317.         Dprintf("Base module `%s' already loaded.\n", basename);
  318.     } else {
  319.         Dprintf("Loading base module `%s' ...\n", basename);
  320.         load_game_module(basemodule, FALSE);
  321.         Dprintf("... Done loading `%s'.\n", basename);
  322.     }
  323.     }
  324. }
  325.  
  326. /* Given a module, attempt to open it. */
  327.  
  328. int
  329. open_module(module, dowarn)
  330. Module *module;
  331. int dowarn;
  332. {
  333.     FILE *fp = NULL;
  334.  
  335.     /* Don't open more than once. */
  336.     if (module->open && dowarn) {
  337.     init_warning("Module \"%s\" is already open, ignoring attempt to reopen",
  338.              module->name);
  339.     return FALSE;
  340.     }
  341.     /* Don't open if already loaded. */
  342.     if (module->loaded && dowarn) {
  343.     init_warning("Module \"%s\" is already loaded, ignoring attempt to reload",
  344.              module->name);
  345.     return FALSE;
  346.     }
  347.     if (module->contents) {
  348.     /* Uninterpreted contents already available, init the ptr. */
  349.     module->sp = module->contents;
  350.     Dprintf("Reading module \"%s\" from string ...\n", module->name);
  351.     } else if ((fp = open_module_library_file(module)) != NULL) {
  352.     /* Found the module in a library directory. */
  353.     Dprintf("Reading module \"%s\" from library file \"%s\" ...\n",
  354.         module->name, module->filename);
  355.     module->fp = fp;
  356.     } else if ((fp = open_module_explicit_file(module)) != NULL) {
  357.     Dprintf("Reading module \"%s\" from file \"%s\" ...\n",
  358.         module->name, module->filename);
  359.     module->fp = fp;
  360.     } else {
  361.     if (dowarn) {
  362.         if (module->name) {
  363.             init_warning("Can't find module \"%s\" anywhere",
  364.                  module->name);
  365.         } else {
  366.             init_warning("Can't find unnamed module anywhere");
  367.         }
  368.     }
  369.     return FALSE;
  370.     }
  371.     /* It worked, mark this module as open. */
  372.     module->open = TRUE;
  373.     return TRUE;
  374. }
  375.  
  376. /* Read info about a side's preferences and setup. */
  377.  
  378. /* This assumes one form only, probably too restrictive. */
  379. /* should read all the forms, use the relevant ones. */
  380. /* (how does this interact with other defaults?) */
  381. /* (should be delayed until player can confirm it...) */
  382.  
  383. /* (update to work like other module stuff? then can use resources etc) */
  384. /* (fix so that correct name can be found reliably) */
  385.  
  386. int
  387. load_side_config(side)
  388. Side *side;
  389. {
  390. #if 0
  391.     FILE *fp;
  392.     Obj *config;
  393.     Module *module;
  394.  
  395.     /* (should incorp config name somehow, also be sys-dependent) */
  396.     module = create_game_module(side->player->name);
  397.  
  398.     if ((module->fp = fopen(module->filename, "r")) != NULL) {
  399.     if ((config = read_form(module->fp,
  400.                 &(module->startlineno),
  401.                 &(module->endlineno)))
  402.         != lispeof) {
  403.         /* interpret the config */
  404.         Dprintf("Interpreting %s config form", side_desig(side));
  405.         Dprintlisp(config);
  406.         Dprintf("\n");
  407.         fill_in_side(side, config, TRUE);
  408.     } else {
  409.         /* no config form in the file */
  410.     }
  411.     } else {
  412.     init_warning("Module \"%s\" could not be opened", module->name);
  413.     /* Not a disaster, keep going */
  414.     }
  415. #endif
  416.     return FALSE;
  417. }
  418.  
  419. /* Read an entire file, attempting to pick up objects in it. */
  420.  
  421. /* (does this interp game-module form twice if description previously
  422.    loaded?) */
  423.  
  424. void
  425. read_forms(module)
  426. Module *module;
  427. {
  428.     Obj *form;
  429.  
  430.     Dprintf("Trying to read a new format file \"%s\"...\n", module->name);
  431.     while ((form = read_form(module->fp,
  432.                  &(module->startlineno),
  433.                  &(module->endlineno)))
  434.        != lispeof) {
  435.     interp_form(module, form);
  436.     }
  437.     /* Clean up after any print forms that might have been done. */
  438.     end_printing_forms();
  439.     Dprintf("... Done reading \"%s\".\n", module->name);
  440. }
  441.  
  442. /* Interpret the given list of variants. */
  443.  
  444. void
  445. do_module_variants(module, lis)
  446. Module *module;
  447. Obj *lis;
  448. {
  449.     int i, found;
  450.     Obj *restset, *varset;
  451.     Variant *var;
  452.  
  453.     if (module->variants == NULL)
  454.       return; /* error? */
  455.     for_all_list(lis, restset) {
  456.     varset = car(restset);
  457.     found = FALSE;
  458.     for (i = 0; module->variants[i].id != lispnil; ++i) {
  459.         var = &(module->variants[i]);
  460.         if (equal(car(varset), var->id)) {
  461.         do_one_variant(module, var, cdr(varset));
  462.         found = TRUE;
  463.         }
  464.     }
  465.     if (!found) {
  466.         read_warning("Mystifying variant");
  467.     }
  468.     }
  469.     /* Now implement all the defaults. */
  470.     for (i = 0; module->variants[i].id != lispnil; ++i) {
  471.     var = &(module->variants[i]);
  472.     if (!var->used)
  473.       do_one_variant(module, var, lispnil);
  474.     }
  475. }
  476.  
  477. static void
  478. do_one_variant(module, var, varsetdata)
  479. Module *module;
  480. Variant *var;
  481. Obj *varsetdata;
  482. {
  483.     int val, caseval;
  484.     int width = 0, height = 0, circumference, latitude, longitude;
  485.     int rtime, rtimeperturn, rtimeperside;
  486.     char *vartypename = c_string(var->id);
  487.     Obj *restcases, *headcase, *rest, *filler, *rawval, *rawcaseval;
  488.  
  489.     if (Debug) {
  490.     if (readerrbuf == NULL)
  491.       readerrbuf = (char *) xmalloc(BUFSIZE);
  492.         sprintlisp(readerrbuf, varsetdata);
  493.         Dprintf("Module %s variant %s being set to `%s'\n",
  494.             module_desig(module), vartypename, readerrbuf);
  495.     }
  496.     switch (keyword_code(vartypename)) {
  497.       case K_WORLD_SEEN:
  498.     val = (varsetdata == lispnil ?
  499.            (var->dflt == lispnil ? FALSE : c_number(eval(var->dflt))) :
  500.            c_number(eval(car(varsetdata))));
  501.     var->hasintvalue = TRUE;
  502.     var->intvalue = val;
  503.     set_g_terrain_seen(val);
  504.     break;
  505.       case K_SEE_ALL:
  506.     val = (varsetdata == lispnil ?
  507.            (var->dflt == lispnil ? FALSE : c_number(eval(var->dflt))) :
  508.            c_number(eval(car(varsetdata))));
  509.     var->hasintvalue = TRUE;
  510.     var->intvalue = val;
  511.     set_g_see_all(val);
  512.     break;
  513.       case K_SEQUENTIAL:
  514.     val = (varsetdata == lispnil ?
  515.            (var->dflt == lispnil ? FALSE : c_number(eval(var->dflt))) :
  516.            c_number(eval(car(varsetdata))));
  517.     var->hasintvalue = TRUE;
  518.     var->intvalue = val;
  519.     set_g_use_side_priority(val);
  520.     break;
  521.       case K_WORLD_SIZE:
  522.           filler = lispnil;
  523.     if (varsetdata != lispnil) {
  524.         filler = varsetdata;
  525.     } else if (var->dflt != lispnil) {
  526.         filler = var->dflt;
  527.     }
  528.     /* Pick the width and height out of the list. */
  529.     if (filler != lispnil) {
  530.         width = c_number(eval(car(filler)));
  531.         filler = cdr(filler);
  532.     }
  533.     if (filler != lispnil) {
  534.         height = c_number(eval(car(filler)));
  535.         filler = cdr(filler);
  536.     } else {
  537.         height = width;
  538.     }
  539.     /* Pick up a circumference if given. */
  540.     if (filler != lispnil) {
  541.         circumference = c_number(eval(car(filler)));
  542.         set_world_circumference(circumference, TRUE);
  543.         filler = cdr(filler);
  544.     }
  545.     /* This is more useful after the circumference has been set. */
  546.     if (width > 0 && height > 0)
  547.       set_area_shape(width, height, TRUE);
  548.     /* Pick up latitude and longitude if given. */
  549.     if (filler != lispnil) {
  550.         latitude = c_number(eval(car(filler)));
  551.         /* (should use a setter routine?) */
  552.         area.latitude = latitude;
  553.         filler = cdr(filler);
  554.     }
  555.     if (filler != lispnil) {
  556.         longitude = c_number(eval(car(filler)));
  557.         /* (should use a setter routine?) */
  558.         area.longitude = longitude;
  559.         filler = cdr(filler);
  560.     }
  561.     /* (should record settings somehow) */
  562.     break;
  563.       case K_REAL_TIME:
  564.           filler = lispnil;
  565.     if (varsetdata != lispnil) {
  566.         filler = varsetdata;
  567.     } else if (var->dflt != lispnil) {
  568.         filler = var->dflt;
  569.     }
  570.     if (filler != lispnil) {
  571.         rtime = c_number(eval(car(filler)));
  572.         filler = cdr(filler);
  573.     } else {
  574.         rtime = 0;
  575.     }
  576.     if (filler != lispnil) {
  577.         rtimeperside = c_number(eval(car(filler)));
  578.         filler = cdr(filler);
  579.     } else {
  580.         rtimeperside = 0;
  581.     }
  582.     if (filler != lispnil) {
  583.         rtimeperturn = c_number(eval(car(filler)));
  584.         filler = cdr(filler);
  585.     } else {
  586.         rtimeperturn = 0;
  587.     }
  588.     /* If the values were specified, tweak the official
  589.        realtime globals. */
  590.     if (rtime > 0)
  591.       set_g_rt_for_game(rtime);
  592.     if (rtimeperside > 0)
  593.       set_g_rt_per_side(rtimeperside);
  594.     if (rtimeperturn > 0)
  595.       set_g_rt_per_turn(rtimeperturn);
  596.     /* (should record settings somehow) */
  597.     break;
  598.       default:
  599.     /* This is the general case. */
  600.     if (varsetdata != lispnil) {
  601.         rawval = car(varsetdata);
  602.     } else if (var->dflt != lispnil) {
  603.         rawval = var->dflt;
  604.     } else {
  605.         rawval = lispnil;
  606.     }
  607.     /* Always evaluate the raw value of the variant. */
  608.     rawval = eval(rawval);
  609.     if (numberp(rawval)) {
  610.         val = c_number(rawval);
  611.         var->hasintvalue = TRUE;
  612.         var->intvalue = val;
  613.     } else {
  614.         val = FALSE;
  615.     }
  616.     for_all_list(var->cases, restcases) {
  617.         headcase = car(restcases);
  618.         rawcaseval = eval(car(headcase));
  619.         if (numberp(rawcaseval))
  620.           caseval = c_number(rawcaseval);
  621.         if (numberp(rawcaseval) && caseval == val) {
  622.         for_all_list(cdr(headcase), rest) {
  623.             interp_form(module, car(rest));
  624.             }
  625.         }
  626.     }
  627.     /* Clean up after printing, might have been print forms in variant. */
  628.     end_printing_forms();
  629.     break;
  630.     }
  631.     /* Flag the variant as having been specified. */
  632.     var->used = TRUE;
  633. }
  634.  
  635. void
  636. init_module_reshape(module)
  637. Module *module;
  638. {
  639.     /* Seed all the reshaping parameters with reasonable values. */
  640.     module->maybe_reshape = TRUE;
  641.     module->subarea_width = area.width;
  642.     module->subarea_height = area.height;
  643.     module->subarea_x = module->subarea_y = 0;
  644.     module->final_subarea_width = area.width;
  645.     module->final_subarea_height = area.height;
  646.     module->final_subarea_x = module->final_subarea_y = 0;
  647.     module->final_width = area.width;  module->final_height = area.height;
  648.     module->final_circumference = world.circumference;
  649.     module->fill_type = 0;
  650. }
  651.  
  652. /* This is true if any actual reshaping is required. */
  653.  
  654. int
  655. reshape_the_output(module)
  656. Module *module;
  657. {
  658.     return (module->maybe_reshape
  659.         && (module->subarea_width != area.width
  660.         || module->subarea_height != area.height
  661.         || module->subarea_x != 0
  662.         || module->subarea_y != 0
  663.         || module->final_subarea_width != area.width
  664.         || module->final_subarea_height != area.height
  665.         || module->final_subarea_x != 0
  666.         || module->final_subarea_y != 0
  667.         || module->final_width != area.width
  668.         || module->final_height != area.height
  669.         || module->final_circumference != world.circumference));
  670. }
  671.  
  672. /* Check if the proposed reshape will actually work. */
  673.  
  674. int
  675. valid_reshape(module)
  676. Module *module;
  677. {
  678.     /* (should check hexagon shaping) */
  679.     if (module->subarea_width > area.width
  680.     || module->subarea_height > area.height)
  681.       return FALSE;
  682.     /* (should check other offsets) */
  683.     if (module->final_width < 3 || module->final_height < 3)
  684.       return FALSE;
  685.     return TRUE;
  686. }
  687.  
  688. /* Close the module. */
  689.  
  690. void
  691. close_module(module)
  692. Module *module;
  693. {
  694.     if (module->sp) {
  695.     module->sp = NULL;
  696.     }
  697.     if (module->fp) {
  698.     fclose(module->fp);
  699.     module->fp = NULL;
  700.     }
  701.     module->open = FALSE;
  702. }
  703.  
  704. /* Return a description of the module. */
  705.  
  706. char *
  707. module_desig(module)
  708. Module *module;
  709. {
  710.     if (moduledesigbuf == NULL)
  711.       moduledesigbuf = xmalloc(BUFSIZE);
  712.     sprintf(moduledesigbuf, "module %s (%s)",
  713.         module->name, (module->title ? module->title : "no title"));
  714.     return moduledesigbuf;
  715. }
  716.  
  717. /* (random code below, should be sent to better places) */
  718.  
  719. #ifdef DEBUGGING
  720. /* Use this to ensure that everything is cool. */
  721.  
  722. void
  723. doublecheck_state(side)
  724. Side *side;
  725. {
  726.     Unit *unit;
  727.  
  728.     for_all_units(unit) {
  729.     if (unit->x < 0 || unit->x >= area.width ||
  730.         unit->y <= 0 || unit->y >= (area.height - 1) ||
  731.         unit->hp <= 0) {
  732.         Dprintf("%s off map hp %d", unit_desig(unit), unit->hp);
  733.     }
  734.     }
  735. }
  736. #endif /* DEBUGGING */
  737.  
  738. void set_u_internal_name(u, s) int u; char *s; { utypes[u].iname = s; }
  739. void set_u_type_name(u, s) int u; char *s; { utypes[u].name = s; }
  740. void set_m_type_name(m, s) int m; char *s; { mtypes[m].name = s; }
  741. void set_t_type_name(t, s) int t; char *s; { ttypes[t].name = s; }
  742.  
  743. /* If a special symbol, we might not have to fail. */
  744.  
  745. int
  746. lazy_bind(sym)
  747. Obj *sym;
  748. {
  749.     int u, m, t;
  750.     Obj *value;
  751.  
  752.     switch (keyword_code(c_string(sym))) {
  753.       case K_USTAR:
  754.     value = lispnil;
  755.     /* Since consing glues onto the front, iterate backwards
  756.        through the types. */
  757.     for (u = numutypes - 1; u >= 0; --u) {
  758.         value = cons(new_utype(u), value);
  759.     }
  760.     break;
  761.       case K_MSTAR:
  762.     value = lispnil;
  763.     for (m = nummtypes - 1; m >= 0; --m) {
  764.         value = cons(new_mtype(m), value);
  765.     }
  766.     break;
  767.       case K_TSTAR:
  768.     value = lispnil;
  769.     for (t = numttypes - 1; t >= 0; --t) {
  770.         value = cons(new_ttype(t), value);
  771.     }
  772.     break;
  773.       default:
  774.     return FALSE;
  775.     }
  776.     setq(sym, value);
  777.     return TRUE;
  778. }
  779.  
  780. int
  781. coerce_to_side_id(x)
  782. Obj *x;
  783. {
  784.     if (numberp(x)) {
  785.     return c_number(x);
  786.     }
  787.     return 0;
  788. }
  789.  
  790. Side *
  791. coerce_to_side(x)
  792. Obj *x;
  793. {
  794.     return side_n(coerce_to_side_id(x));
  795. }
  796.  
  797. int
  798. coerce_to_unit_id(x)
  799. Obj *x;
  800. {
  801.     if (numberp(x)) {
  802.     return c_number(x);
  803.     }
  804.     return 0;
  805. }
  806.  
  807. Unit *
  808. coerce_to_unit(x)
  809. Obj *x;
  810. {
  811.     return find_unit(coerce_to_unit_id(x));
  812. }
  813.